import View from 'ol/View'
import Map from 'ol/Map'
import { ScaleLine } from 'ol/control'
import { defaults as defaultInteractions } from 'ol/interaction'
import { DEFAULT_OPTS } from './constant'
import EventEmit from './event/eventEmit'
import { isArray } from './utils/index.js'
import layerMethods from './layer/index.js'

export default class Olmap extends EventEmit {

  constructor(config = {}) {
    super()
    const opts = { ...DEFAULT_OPTS, ...config }
    initMap.call(this, opts)
  }
  setMapCenter (center) {
    if (!isArray(center)) {
      throw Error('setMapCenter方法入参数格式需为Array类型')
    }
    const [lng, lat] = center
    if (Number(lng) > 180 || Number(lat) > 90) {
      throw Error(`经纬度范围错误:${center}`)
    }
    this.animate({ center })
  }
  animate (options) {
    const { center, zoom, duration } = options || {}
    const config = { duration }
    zoom && (config.zoom = parseInt(zoom))
    center && (config.center = center)
    this.map.getView().animate(...config)
  }
  /**
   * 地图放大到某个区域
   * @param {*} extent 范围 
   * @param {*} padding 边距 
   * @param {*} duration 动画持续时间（毫秒）
   */
  fitExtent (options = {}) {
    const { extent, padding = [0, 0, 0, 0], duration = 0 } = options || {}
    this.map.getView().fit(extent, {
      duration,
      padding,
    })
  }
  /**
  * 自定义事事件回调
  * @param {String} type 事件类型
  * @param {Function} callback 回调函数
  */
  on (type, callback) {
    if (typeof callback !== 'function') return
    if (!this._eventList) {
      this._eventList = {}
    }
    this._eventList[type] = callback
    this.listen(type, callback)
  }
  /**
   * 获取像素对应的实际距离
   */
  getDistanceFromPixel (num = 50) {
    const resolution = this.map.getView().getResolution() // 分辨率
    return parseInt(Math.round(resolution * num * 100) / 100)
  }
}

const prototypeMethods = { ...layerMethods }
Object.keys(prototypeMethods).forEach((key) => {
  Object.defineProperty(Olmap.prototype, key, {
    value: prototypeMethods[key]
  })
})

/**
 * 初始化地图
 * @param {*} options 配置项
 */
function initMap (options) {
  const {
    target,
    center,
    wmtsLayers = [],
    zoom,
    minZoom,
    maxZoom,
    rotation,
    projection,
    mouseWheelZoom,
    doubleClickZoom,
    pinchRotate,
    pinchZoom,
    scaleLine
  } = options || {}

  const view = new View({
    // center: this.transformLonLat(center),
    projection,
    rotation,
    zoom,
    minZoom,
    maxZoom,
    constrainResolution: true
  })

  const interactions = defaultInteractions({
    pinchRotate,
    doubleClickZoom,
    pinchZoom,
    mouseWheelZoom
  }).extend([
    // new Drag(this)
  ])

  const map = new Map({
    target,
    view,
    interactions
  })


  Object.defineProperty(this, 'map', { value: map })
  // 添加比例尺
  if (scaleLine) {
    map.addControl(new ScaleLine({ units: 'metric' }))
  }
  // 加载wmts图层
  if (wmtsLayers.length) {
    initWMTSLayer.call(this, options)
  }
  setTimeout(() => {
    this.trigger('load')
  }, 0)
}
/**
 * 初始化WMTS图层
 * @param {*} options 
 */
function initWMTSLayer (options) {
  const { wmtsLayers = [], showLayerGruopId } = options || {}
  const wmtsLayerGroup = wmtsLayers.reduce((total, current) => {
    const { group = {} } = current
    if (!total[group.id]) {
      total[group.id] = []
    }
    total[group.id].push(current)
    return total
  }, {})
  console.log('wmtsLayerGroup', wmtsLayerGroup)
  Object.keys(wmtsLayerGroup).forEach((key, i) => {
    const layers = wmtsLayerGroup[key].map((v) => layerMethods.addWMTSMapLayer.call(this, v))
    const layerGroup = layerMethods.createLayerGroup.call(this, {
      groupName: key,
      layers,
      zIndex: i + 1
    })
    layerGroup.setVisible(showLayerGruopId === key)
    this.map.addLayer(layerGroup)
  })
  const layers = this.map.getLayers().getArray()
  Object.defineProperty(this, 'layers', { value: layers })
}

